Discourse-oriented German Climate Change Glossary - R Notebook

Prerequisites

To open and use this file you need to install the following: - R, RStudio

#install.packages("quanteda")
#install.packages("readtext")
#install.packages("wordcloud")
#install.packages("RColorBrewer")
#install.packages("wordcloud2")
#install.packages("tidyverse")
#install.packages("tm")
#install.packages("quanteda.textmodels")
#install.packages("quanteda.textstats")
#install.packages("quanteda.textplots")
#install.packages("broom")

1. Web Scraping with Trafilatura

This step is necessary to get the text data from the websites. In a first step, a list of links of all the subpages of a website is being created. Next, this list of links is processed and the text data is being retrieved and saved in .txt files. This was done in the terminal, not in R.

# run link discovery through website and store the resulting links in a file
$ trafilatura --sitemap "https://www.klimareporter.de" --list > klimareporterlinks.txt

# to process list of links and get texts
$ trafilatura -i klimareporterlinks.txt -o klimareporter_texts

2. Corpus Creation

Load required libraries

# load libraries
library(quanteda)
library(readtext)
library(wordcloud)
library(RColorBrewer)
library(wordcloud2)
library(tidyverse)
library(tm)
library("textcat")
library("quanteda.textplots")
library("quanteda.textstats")
library("gsubfn")
library("spacyr")
library(broom)

spacy_initialize(model = "de_core_news_sm")

To open the previously created text files, we need to run the following code:

# you can get the current directory for importing the text files by setting current directory and open relative path from there with
#texts <- readtext("path/*")

#setwd("/Users/anna/Documents/textmining/textmining_climate")

# climate change activists texts
fff_de_texts <- readtext("text_files/pro/fff_de_texts/*")
ikem_texts <- readtext("text_files/pro/ikem_texts/*")
klimarep_texts <- readtext("text_files/pro/klimareporter_texts/*")
klimafakten_texts <- readtext("text_files/pro/klimafakten_texts/*")
zero_texts <- readtext("text_files/pro/germanzero_texts/*")
komma_texts <- readtext("text_files/pro/komma_texts/*")

# climate change sceptics texts
eike_texts <- readtext("text_files/contra/eike_texts/*")

Building a Corpus

# build corpus for each text with "origin" tag
# specify language for each text to get rid of non-German texts 

# activists
fff_de_corpus <- corpus(fff_de_texts)
docvars(fff_de_corpus, "origin") <- "fff_de"
docvars(fff_de_corpus, "language") <- textcat(fff_de_corpus)
fff_de_corpus <- corpus_subset(fff_de_corpus, language == "german", drop_docid = TRUE)

ikem_corpus <- corpus(ikem_texts)
docvars(ikem_corpus, "origin") <- "ikem"
docvars(ikem_corpus, "language") <- textcat(ikem_corpus)
ikem_corpus <- corpus_subset(ikem_corpus, language == "german", drop_docid = TRUE)

klimarep_corpus <- corpus(klimarep_texts)
docvars(klimarep_corpus, "origin") <- "kr"
docvars(klimarep_corpus, "language") <- textcat(klimarep_corpus)
klimarep_corpus <- corpus_subset(klimarep_corpus, language == "german", drop_docid = TRUE)

klimafakten_corpus <- corpus(klimafakten_texts)
docvars(klimafakten_corpus, "origin") <- "kf"
docvars(klimafakten_corpus, "language") <- textcat(klimafakten_corpus)
klimafakten_corpus <- corpus_subset(klimafakten_corpus, language == "german", drop_docid = TRUE)

zero_corpus <- corpus(zero_texts)
docvars(zero_corpus, "origin") <- "zero"
docvars(zero_corpus, "language") <- textcat(zero_corpus)
zero_corpus <- corpus_subset(zero_corpus, language == "german", drop_docid = TRUE)

komma_corpus <- corpus(komma_texts)
docvars(komma_corpus, "origin") <- "gk"
docvars(komma_corpus, "language") <- textcat(komma_corpus)
komma_corpus <- corpus_subset(komma_corpus, language == "german", drop_docid = TRUE)

# sceptics
eike_corpus <- corpus(eike_texts)
docvars(eike_corpus, "origin") <- "eike"
docvars(eike_corpus, "language") <- textcat(eike_corpus)
eike_corpus <- corpus_subset(eike_corpus, language == "german", drop_docid = TRUE)

# build a PRO corpus for all activists texts 
# create a "group" tag with value "activists"
pro_corpus <- fff_de_corpus+ikem_corpus+klimarep_corpus+klimafakten_corpus+zero_corpus+komma_corpus
docvars(pro_corpus, "group") <- "activists"

# build a CONTRA corpus for all sceptics texts 
# create a "group" tag with value "sceptics"
contra_corpus <- eike_corpus
docvars(contra_corpus, "group") <- "sceptics"

Create Subcorpora (2000 texts each)

# get random sample corpus for activists
pro2000 <- corpus_sample(pro_corpus, size = 2000)

# get random sample corpus for sceptics
contra2000 <- corpus_sample(contra_corpus, size = 2000)

# create "full" (combined) corpus with pro and contra sample 
full_corpus <- pro2000+contra2000

# get id number for corpus
docvars(pro2000, "id") <- paste(1:ndoc(pro2000))
docvars(contra2000, "id") <- paste(1:ndoc(contra2000))

Save corpus files in .rds format

# save corpus files as .rds file for later use
saveRDS(full_corpus, "corpora/full_corpus.rds")

saveRDS(pro_corpus, "corpora/pro_corpus.rds")
saveRDS(contra_corpus, "corpora/contra_corpus.rds")

saveRDS(pro2000, "corpora/pro2000.rds")
saveRDS(contra2000, "corpora/contra2000.rds")

# activists
saveRDS(fff_de_corpus, "corpora/fff_de_corpus.rds")
saveRDS(ikem_corpus, "corpora/ikem_corpus.rds")
saveRDS(klimarep_corpus, "corpora/klimarep_corpus.rds")
saveRDS(klimafakten_corpus, "corpora/klimafakten_corpus.rds")
saveRDS(zero_corpus, "corpora/zero_corpus.rds")
saveRDS(komma_corpus, "corpora/komma_corpus.rds")

# sceptics
saveRDS(eike_corpus, "corpora/eike_corpus.rds")

3. Corpus Statistics

Load existing corpus files

# load corpus files 
full_corpus = readRDS("corpora/full_corpus.rds")

pro_corpus = readRDS("corpora/pro_corpus.rds")
contra_corpus = readRDS("corpora/contra_corpus.rds")

pro2000 = readRDS("corpora/pro2000.rds")
contra2000 = readRDS("corpora/contra2000.rds")

# optional: load 
fff_de_corpus = readRDS("corpora/fff_de_corpus.rds")
ikem_corpus = readRDS("corpora/ikem_corpus.rds")
klimarep_corpus = readRDS("corpora/klimarep_corpus.rds")
klimafakten_corpus = readRDS("corpora/klimafakten_corpus.rds")
zero_corpus = readRDS("corpora/zero_corpus.rds")
komma_corpus = readRDS("corpora/komma_corpus.rds")
eike_corpus = readRDS("corpora/eike_corpus.rds")

Exploring the corpus

First, we want to have a look at the information each of the corpora gives us: - types - tokens - number of sentences - origin - language - group - id

# retrieve overview of corpus information
summary(pro2000, n = 10)
Corpus consisting of 2000 documents, showing 10 documents:

              Text Types Tokens Sentences origin language     group id
    ikem_01086.txt   207    551        20   ikem   german activists  1
    ikem_01158.txt    27     30         2   ikem   german activists  2
 gerzero_00045.txt    40     44         3   zero   german activists  3
    ikem_01396.txt    27     30         2   ikem   german activists  4
    ikem_01532.txt   216    855        28   ikem   german activists  5
    ikem_01553.txt   169    291        12   ikem   german activists  6
    ikem_00191.txt   268    462        18   ikem   german activists  7
      kr_00033.txt   323    575        31     kr   german activists  8
    ikem_00343.txt    26     35         1   ikem   german activists  9
    ikem_01502.txt    12     12         1   ikem   german activists 10
summary(contra2000, n=10)
Corpus consisting of 2000 documents, showing 10 documents:

           Text Types Tokens Sentences origin language    group id
 eike_10314.txt  2894  11548       545   eike   german sceptics  1
 eike_06091.txt   452    867        41   eike   german sceptics  2
 eike_05388.txt    21     26         2   eike   german sceptics  3
 eike_09888.txt  1728   4534       234   eike   german sceptics  4
 eike_01977.txt    44     50         3   eike   german sceptics  5
 eike_06182.txt    46     56         5   eike   german sceptics  6
 eike_04363.txt   503   1014        56   eike   german sceptics  7
 eike_08508.txt    20     25         2   eike   german sceptics  8
 eike_05567.txt   596   1266        58   eike   german sceptics  9
 eike_03672.txt    18     21         1   eike   german sceptics 10

Plotting Number of Sentences

The overview of the corpus information reveals that the sceptics corpus may consist of much longer texts (see “Sentences” counts) than the activists corpus. We want to re-check this information by plotting the sentences coutns for a subset of the data.

# retrieve corpus information (only 50 entries)
contra2000_sum <- summary(contra2000, n=50)
pro2000_sum <- summary(pro2000, n=50)

# create plots from corpus information
ggplot(pro2000_sum, aes(id, Sentences, group=1)) +
  geom_line() + 
  geom_point() +
  theme(axis.text.x = element_text(angle=0, vjust=1, hjust=1)) + 
  ggtitle("Sentences Pro2000")


ggplot(contra2000_sum, aes(id, Sentences, group=1)) +
  geom_line() + 
  geom_point() +
  theme(axis.text.x = element_text(angle=0, vjust=1, hjust=1)) + 
  ggtitle("Sentences Contra2000")

Now we can caluculate the mean count of the sentences by running the following code.

sents_pro = summary(pro2000, n=ndoc(pro2000))$Sentences
mean(sents_pro)
[1] 24.7015
sents_con = summary(contra2000, n=ndoc(contra2000))$Sentences
mean(sents_con)
[1] 73.8075

The results show, that the texts of the activists corpus consist of averagely 24,7 sentences, meanwhile the texts of the sceptics corpus have an average number of sentences of 73,8. This suggests that the texts of the sceptics corpus are much longer than the ones in the other corpus.

Type-Token Ratio (TTR)

Now let’s have a look at the TTR of both corpora.

The closer the value approximates to 1, the greater the lexical richness. Both corpora appear to have very similar TTRs and thus seem to reveal very similar lexical richness of the texts.

4. Empirical Work

Create a Document-Feature Matrix (dfm), load stop lists

# retrieve stoplists
de_stopwords <- stopwords::stopwords("de", source="snowball")
en_stopwords <- stopwords::stopwords("en", source="snowball" )
custom_stopwords <- read.table("de_complete.txt", header=F, sep="\n")

# add own stopwords 
full_stopwords <- c(de_stopwords, "dass", "=", "the", "seit", "ab", "beim", "\n", "mal", "c", "|", "m", "kommentare", "neueste", "gepostet", custom_stopwords, en_stopwords)
de_stopwords1 <- c(de_stopwords, "dass", "=", "the", "seit", "ab", "beim", "\n", "mal", "c", "\\|","|", "m", "kommentare", "neueste", "gepostet", "admin", "cookies", "inhalte", "inhalt", "newsletter", "posten", "zugriff", "passwort", "geschützt", "seite", "website", "webseite", "and", "0", "1", "2", "3","4","5","6","7","8","9", "mfg","w","t","wer")


# create dfm
dfm_p2000 <- dfm(pro2000, remove=full_stopwords, remove_punct=TRUE, remove_numbers=TRUE, tolower=TRUE)
Warnung: 'dfm.corpus()' is deprecated. Use 'tokens()' first.
Warnung: '...' should not be used for tokens() arguments; use 'tokens()' first.
Warnung: 'remove' is deprecated; use dfm_remove() instead
dfm_c2000 <- dfm(contra2000, remove=full_stopwords, remove_punct=TRUE, remove_numbers=TRUE, tolower=TRUE)
Warnung: 'dfm.corpus()' is deprecated. Use 'tokens()' first.
Warnung: '...' should not be used for tokens() arguments; use 'tokens()' first.
Warnung: 'remove' is deprecated; use dfm_remove() instead

Let’s have a look at the dfm of both corpora:

# pro corpus dfm
dfm_p2000
Document-feature matrix of: 2,000 documents, 60,294 features (99.72% sparse) and 4 docvars.
                   features
docs                ikem aktuellen eeg-erfahrungsbericht beteiligt webseite bundesministeriums wirtschaft
  ikem_01086.txt       7         1                     2         2        2                  2          3
  ikem_01158.txt       1         0                     0         0        0                  0          0
  gerzero_00045.txt    0         0                     0         0        0                  0          0
  ikem_01396.txt       1         0                     0         0        0                  0          0
  ikem_01532.txt       3         0                     0         0        0                  1          3
  ikem_01553.txt       1         0                     0         0        0                  0          0
                   features
docs                energie energiewende wurde
  ikem_01086.txt          3            2     2
  ikem_01158.txt          0            0     0
  gerzero_00045.txt       0            0     0
  ikem_01396.txt          0            0     0
  ikem_01532.txt          0            0     1
  ikem_01553.txt          2            0     1
[ reached max_ndoc ... 1,994 more documents, reached max_nfeat ... 60,284 more features ]
# contra corpus dfm
dfm_c2000
Document-feature matrix of: 2,000 documents, 146,894 features (99.70% sparse) and 4 docvars.
                features
docs             modellierung kiehl trenberth wirft zahlreiche fragen gibt deutliche abweichungen
  eike_10314.txt            6     7         6     1          1      3   14         1            1
  eike_06091.txt            0     0         0     0          0      0    1         0            0
  eike_05388.txt            0     0         0     0          0      0    0         0            0
  eike_09888.txt            0     0         0     0          1      1    9         0            0
  eike_01977.txt            0     0         0     0          0      0    0         0            0
  eike_06182.txt            0     0         0     0          0      0    0         0            0
                features
docs             satelliten
  eike_10314.txt          4
  eike_06091.txt          0
  eike_05388.txt          0
  eike_09888.txt          0
  eike_01977.txt          0
  eike_06182.txt          0
[ reached max_ndoc ... 1,994 more documents, reached max_nfeat ... 146,884 more features ]

The document-feature matrix basically consists of rows for each text and columns for each word in the texts. The column values reflect how many times a term appears in a text - if a term does not occur in a text, its value is zero.

Corpus Cleaning

To clean the corpora lemmatization and application of stop lists (see previous step) was performed. For the lemmatization, the spacyr library was used.

Info: This piece of code takes some time to run.

# parse the pro corpus with spacy function and retrieve lemma for each token
sp_pro2000 <- spacy_parse(pro2000, pos=FALSE, entity=FALSE, dependency=FALSE)
Warnung in spacy_parse.character(pro2000, pos = FALSE, entity = FALSE, dependency = FALSE)
  lemmatization may not work properly in model 'de_core_news_sm'
sp_pro2000$token <- sp_pro2000$lemma

# create lemmatized version of dfm for activists corpus
sp_dfm_p2000 <- as.tokens(sp_pro2000)%>%
  dfm(remove=full_stopwords, remove_punct=TRUE, remove_numbers=TRUE, tolower=TRUE)
Warnung: '...' should not be used for tokens() arguments; use 'tokens()' first.
Warnung: 'remove' is deprecated; use dfm_remove() instead
# parse the contra corpus with spacy function and retrieve lemma for each token
sp_contra2000 <- spacy_parse(contra2000, pos=FALSE, entity=FALSE, dependency=FALSE)
Warnung in spacy_parse.character(contra2000, pos = FALSE, entity = FALSE, 
  lemmatization may not work properly in model 'de_core_news_sm'
sp_contra2000$token <- sp_contra2000$lemma

# create lemmatized version of dfm for sceptics corpus
sp_dfm_c2000 <- as.tokens(sp_contra2000)%>%
  dfm(remove=full_stopwords, remove_punct=TRUE, remove_numbers=TRUE, tolower=TRUE)
Warnung: '...' should not be used for tokens() arguments; use 'tokens()' first.
Warnung: 'remove' is deprecated; use dfm_remove() instead
# parse the full corpus with spacy function and retrieve lemma for each token
sp_full <- spacy_parse(full_corpus, pos=FALSE, entity=FALSE, dependency=FALSE)
Warnung in spacy_parse.character(full_corpus, pos = FALSE, entity = FALSE, 
  lemmatization may not work properly in model 'de_core_news_sm'
sp_full$token <- sp_full$lemma

# create lemmatized version of dfm for sceptics corpus
sp_dfm_full <- as.tokens(sp_full) %>%
  dfm(remove=full_stopwords, remove_punct=TRUE, remove_numbers=TRUE, tolower=TRUE)
Warnung: '...' should not be used for tokens() arguments; use 'tokens()' first.
Warnung: 'remove' is deprecated; use dfm_remove() instead

Comment: The German lemmatization with spacyr is not very accurate. A lot of compounds do not get lemmatized at all and therefore appear multiple times (in all possible forms) in the dfm.

Most frequent terms

With the help of ´topfeatures´ we can check the most frequently occuring terms for each dfm.

# check top 50 terms for activists corpus
topfeatures(sp_dfm_p2000, n=50)
        mehr          uhr         ikem       mensch         jahr         weit 
        4284         3497         2655         2463         2062         1698 
 deutschland        geben      energie        thema      aktuell       sollen 
        1643         1603         1592         1401         1362         1322 
        groß        gehen  klimaschutz          gut        sowie        immer 
        1317         1301         1289         1276         1209         1156 
     bleiben  information       müssen        schon        dabei       future 
        1151         1150         1144         1084         1019          992 
      arbeit       stehen energiewende      politik       finden        welch 
         976          925          900          895          891          886 
        land      projekt         ziel      wichtig       berlin       kommen 
         876          870          862          852          846          838 
     fridays     erfahren          jed      zukunft   klimakrise   newsletter 
         831          825          815          813          796          779 
        ganz          neu       rahmen     laufende      möglich         erst 
         769          750          747          740          735          721 
    anmelden        frage 
         719          717 
# check top 50 terms for sceptics corpus 
topfeatures(sp_dfm_c2000, n=50)
       jahr       geben        mehr       schon       immer         gut      kommen         co2        weit 
       8926        6744        6044        4549        4348        3955        3880        3839        3715 
         ja       gehen deutschland      sollen      mensch       welch        groß       sagen         jed 
       3702        3700        3597        3490        3427        3325        3323        3265        3177 
    energie        hoch       wenig      zeigen        ganz      global  temperatur           °      müssen 
       3012        2869        2864        2776        2684        2652        2587        2568        2393 
      sehen        herr     einfach   natürlich       klima        zeit       strom      stehen       heute 
       2370        2249        2217        2207        2207        2149        2130        2101        2073 
     finden       frage   erwärmung        erst klimawandel        etwa        land      liegen        welt 
       2042        2020        1979        1974        1951        1949        1901        1900        1863 
        wer       genau      wissen  atmosphäre         tun 
       1835        1811        1764        1754        1754 

Since those lists are not easy to handle, we will create a plot of the information in the following sections.

Plotting Frequencies

To plot the most frequent words of each corpus, let’s run the following code:

# get frequencies of a sample of 50 words from the corpora
freq_p2000 <- textstat_frequency(sp_dfm_p2000, n=50)
freq_c2000 <- textstat_frequency(sp_dfm_c2000, n=50)

# create frequency plots
plot_p2000$feature <- with(freq_p2000, reorder(feature, -frequency))
plot_c2000$feature <- with(freq_c2000, reorder(feature, -frequency))

# create plot for activists corpus word frequencies
plot1 <- ggplot(freq_p2000, aes(x=feature, y=frequency)) + 
  geom_point()+ggtitle("P2000 Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot1


# create plot for sceptics corpus word frequencies
plot2 <- ggplot(freq_c2000, aes(x=feature, y=frequency)) + 
  geom_point()+ ggtitle("C2000 Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1)) 
plot2

This already gives us a first impression of the content of the corpora texts.

Nevertheless, we are particularly interested in the word frequencies of German climate change compound nouns. Accordingly, we start with the retrieval of terms starting with “klima” to hopefully get some climate change compounds. In the enxt step, again we retrieve the frequencies of the words and create plots for both corpora.

# create a sample of the dfm with all words starting with "klima..." 
klima_p2000 <- dfm_select(sp_dfm_p2000, pattern="klima*")
klima_c2000 <- dfm_select(sp_dfm_c2000, pattern="klima*")

# retrieve frequencies for a sample of 50 words 
freq_klima_p2000 <- textstat_frequency(klima_p2000, n=50)
freq_klima_c2000 <- textstat_frequency(klima_c2000, n=50)

# create frequency plots for "klima" words
freq_klima_p2000$feature <- with(freq_klima_p2000, reorder(feature, -frequency))
freq_klima_c2000$feature <- with(freq_klima_c2000, reorder(feature, -frequency))

# create plot for activists corpus "klima" word frequencies
plot3 <- ggplot(freq_klima_p2000, aes(x=feature, y=frequency)) + 
  geom_point()+ggtitle("P2000 'Klima' Word Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot3


# create plot for scpetics corpus "klima" word frequencies
plot4 <- ggplot(freq_klima_c2000, aes(x=feature, y=frequency)) + 
  geom_point()+ ggtitle("C2000 'Klima' Word Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1)) 
plot4

In the following step we retrieve lists of the terms which only appear in one of the Top50 lists. For activists group:

# get list of climate change compounds only appearing in top50 for activists 
setdiff(freq_klima_p2000$feature, freq_klima_c2000$feature)
 [1] "klimapolitische"             "klimagerechtigkeit"         
 [3] "klimastreik"                 "klimaneutralität"           
 [5] "klimafinanzierung"           "klimaschutzmaßnahmen"       
 [7] "klimareporter"               "klimaschutzgesetz"          
 [9] "klimaschutzziele"            "klimanotstand"              
[11] "klimacamp"                   "klimapaket"                 
[13] "klimagerechte"               "klimakommunikation"         
[15] "klimaschädlichen"            "klimafreundliche"           
[17] "klimafakten.de"              "klimaschädliche"            
[19] "klimabewegung"               "klimaneutrale"              
[21] "klimagerechtigkeitsbewegung" "klimaplan"                  
[23] "klimakonferenzen"            "klimastreiks"               
[25] "klimawissen"                 "klimaschutzpolitik"         
[27] "klimaabkommens"              "klimapolitischen"           
[29] "klimawahl"                   "klimazielen"                
[31] "klimaneutralen"              "klimaziel"                  
[33] "klimafreundlichen"           "klimagesetz"                

For sceptics group:

# get list of climate change compounds only appearing in top50 for activists 
setdiff(freq_klima_c2000$feature, freq_klima_p2000$feature)
 [1] "klimawissenschaft"    "klimamodelle"         "klimawissenschaftler"
 [4] "klimasensitivität"    "klimamodellen"        "klimaleugner"        
 [7] "klimaretter"          "klimatologie"         "klimaänderungen"     
[10] "klimaalarmisten"      "klimaskeptiker"       "klimarettung"        
[13] "klimafragen"          "klimatisch"           "klimasystem"         
[16] "klimahysterie"        "klimakirche"          "klimaentwicklung"    
[19] "klima-alarmisten"     "klimaretter.info"     "klimagipfel"         
[22] "klimaaktivisten"      "klimadebatte"         "klimatologen"        
[25] "klimamodell"          "klimaexperten"        "klimafolgenforschung"
[28] "klimaveränderungen"   "klimaschau"           "klimareligion"       
[31] "klima-alarmismus"     "klimaschutzplan"      "klimavertrag"        
[34] "klimahysteriker"     

TF-IDF

To get weighted frequencies of the corpora, it is necessary to have a look at the tf-idf (term frequency-inverse document freqeuncy) of the words.

# weighted words
p2000_weight <- dfm_weight(sp_dfm_p2000, scheme="prop")
c2000_weight <- dfm_weight(sp_dfm_c2000, scheme="prop")

relfreq_p2000 <- textstat_frequency(p2000_weight, n=50)
relfreq_c2000 <- textstat_frequency(c2000_weight, n=50)

#tfidf
p2000_tfidf <- dfm_tfidf(sp_dfm_p2000, scheme_tf = "prop", scheme_df = "inverse")
c2000_tfidf <- dfm_tfidf(sp_dfm_c2000, scheme_tf = "prop", scheme_df = "inverse")

#plot3 <- with(relfreq_p2000, reorder(feature, -freqency))
relfreq_p2000$feature <- with(relfreq_p2000, reorder(feature, -frequency))
plot3 <- ggplot(relfreq_p2000, aes(x=feature, y=frequency)) + 
  geom_point()+ggtitle("P2000 Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
#ggsave(plot=plot1, width = 10, height = 5, dpi=300, filename="klima_eike_plot.jpeg" )
plot3

# weighted words
p2000_klima_weight <- dfm_weight(klima_p2000, scheme="prop")
c2000_klima_weight <- dfm_weight(klima_c2000, scheme="prop")

relfreq_p2000 <- textstat_frequency(p2000_klima_weight, n=50)
relfreq_c2000 <- textstat_frequency(c2000_klima_weight, n=50)

#tfidf
p2000_tfidf <- dfm_tfidf(sp_dfm_p2000, scheme_tf = "prop", scheme_df = "inverse")
c2000_tfidf <- dfm_tfidf(sp_dfm_c2000, scheme_tf = "prop", scheme_df = "inverse")

relfreq_p2000$feature <- with(relfreq_p2000, reorder(feature, -frequency))
plot7 <- ggplot(relfreq_p2000, aes(x=feature, y=frequency)) + 
  geom_point()+ggtitle("P2000 Klima Words - Relative Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot7


relfreq_c2000$feature <- with(relfreq_c2000, reorder(feature, -frequency))
plot8 <- ggplot(relfreq_c2000, aes(x=feature, y=frequency)) + 
  geom_point()+ggtitle("C2000 Klima Words - Relative Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot8

p2000_tfidf <- dfm_tfidf(klima_p2000, scheme_tf = "prop", scheme_df = "inverse")
c2000_tfidf <- dfm_tfidf(klima_c2000, scheme_tf = "prop", scheme_df = "inverse")


pro_freq_tfidf <- p2000_tfidf %>%
  textstat_frequency(n=20, force=TRUE)

con_freq_tfidf <- c2000_tfidf %>%
  textstat_frequency(n=20, force=TRUE)

tplot_tfidf_p2000 <- ggplot(data=pro_freq_tfidf,
                      aes(x=factor(nrow(pro_freq_tfidf):1),
                          y=frequency)) +
  geom_point() +
  ggtitle("P2000 'Klima' Words - Relative Frequencies")+
  coord_flip() +
  scale_x_discrete(breaks=factor(nrow(pro_freq_tfidf):1),
                   labels=pro_freq_tfidf$feature) +
  labs(x=NULL, y="tf-idf")

tplot_tfidf_p2000


tplot_tfidf_c2000 <- ggplot(data=con_freq_tfidf,
                      aes(x=factor(nrow(con_freq_tfidf):1),
                          y=frequency)) +
  geom_point() +
  ggtitle("C2000 'Klima' Words - Relative Frequencies")+
  coord_flip() +
  scale_x_discrete(breaks=factor(nrow(con_freq_tfidf):1),
                   labels=con_freq_tfidf$feature) +
  labs(x=NULL, y="tf-idf")

tplot_tfidf_c2000

Comparison of Groups/Origin

Additionally, let’s have a look at the climate change terms for each website we created our corpora from. All except from EIKE are used to construct the activists corpus.

The following plot provides a lot of information about the usage of terms between both groups - activists and sceptics.

p+labs(colour="Group")
Warnung: Removed 1 rows containing missing values (geom_segment).
Warnung: Removed 1 rows containing missing values (geom_point).

Word Context

Collocations

p2000_colls

c2000_colls
p2000_colls$collocation <- with(p2000_colls, reorder(collocation, -count))
plot9 <- ggplot(p2000_colls, aes(x=collocation, y=count)) + 
  geom_point()+ggtitle("P2000 Collocation Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot9 

ggsave(plot=plot9, width = 10, height = 5, dpi=300, filename="p2000_colls.png")


c2000_colls$collocation <- with(c2000_colls, reorder(collocation, -count))
plot10 <- ggplot(c2000_colls, aes(x=collocation, y=count)) + 
  geom_point()+ggtitle("C2000 Collocation Frequencies")+
  theme(axis.text.x = element_text(angle=90,hjust=1))
plot10

ggsave(plot=plot10, width = 10, height = 5, dpi=300, filename="c2000_colls.png")

Keyness

# Create a dfm grouped by president
group_dfm <- tokens(full_corpus, remove_punct = TRUE) %>%
  tokens_remove(de_stopwords1) %>%
  tokens_group(groups = group) %>%
  dfm()

group_dfm_klima <- dfm_select(group_dfm, pattern ="klima*")

# Calculate keyness and determine Trump as target group
result_keyness <- textstat_keyness(corp_dfm_klima, target = "activists")

# Plot estimated word keyness
textplot_keyness(result_keyness, margin=0.2, n=15, color=c("lightblue", "red")) 

Keyword in Context

kwic_pro <- kwic(pro2000, pattern="klimaschutz", window=5) %>%
  as_tibble()
Warnung: 'kwic.corpus()' is deprecated. Use 'tokens()' first.
head(kwic_pro, n=20)

#write.csv(kwic_pro, "kwic_pro_klimaschutz.csv")
kwic_con <- kwic(contra2000, pattern="klimaschutz", window=5) %>%
  as_tibble()
Warnung: 'kwic.corpus()' is deprecated. Use 'tokens()' first.
head(kwic_con, n=20)
kwic_con <- kwic(contra2000, pattern="klimakrise", window=5) %>%
  as_tibble()
Warnung: 'kwic.corpus()' is deprecated. Use 'tokens()' first.
head(kwic_con, n=20)
kwic_con <- kwic(contra2000, pattern="klimahysterie", window=5) %>%
  as_tibble()
Warnung: 'kwic.corpus()' is deprecated. Use 'tokens()' first.
head(kwic_con, n=20)

write.csv(head(kwic_con, n=20), "kwic_con_klimahysterie.csv")
kwic_pro <- kwic(pro2000, pattern="klimakrise", window=5) %>%
  as_tibble()
Warnung: 'kwic.corpus()' is deprecated. Use 'tokens()' first.
head(kwic_pro, n=20)

write.csv(head(kwic_pro, n=20), "kwic_pro_klimakrise.csv")
LS0tCnRpdGxlOiAiVGV4dCBNaW5pbmcgaW4gU29jaWFsIFNjaWVuY2VzIC0gUXVhbnRlZGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIERpc2NvdXJzZS1vcmllbnRlZCBHZXJtYW4gQ2xpbWF0ZSBDaGFuZ2UgR2xvc3NhcnkgLSBSIE5vdGVib29rIAoKIyMjIFByZXJlcXVpc2l0ZXMKVG8gb3BlbiBhbmQgdXNlIHRoaXMgZmlsZSB5b3UgbmVlZCB0byBpbnN0YWxsIHRoZSBmb2xsb3dpbmc6Ci0gUiwgUlN0dWRpbwpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoInF1YW50ZWRhIikKI2luc3RhbGwucGFja2FnZXMoInJlYWR0ZXh0IikKI2luc3RhbGwucGFja2FnZXMoIndvcmRjbG91ZCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQojaW5zdGFsbC5wYWNrYWdlcygid29yZGNsb3VkMiIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQojaW5zdGFsbC5wYWNrYWdlcygidG0iKQojaW5zdGFsbC5wYWNrYWdlcygicXVhbnRlZGEudGV4dG1vZGVscyIpCiNpbnN0YWxsLnBhY2thZ2VzKCJxdWFudGVkYS50ZXh0c3RhdHMiKQojaW5zdGFsbC5wYWNrYWdlcygicXVhbnRlZGEudGV4dHBsb3RzIikKI2luc3RhbGwucGFja2FnZXMoImJyb29tIikKYGBgCgojIyAxLiBXZWIgU2NyYXBpbmcgd2l0aCBUcmFmaWxhdHVyYQoKVGhpcyBzdGVwIGlzIG5lY2Vzc2FyeSB0byBnZXQgdGhlIHRleHQgZGF0YSBmcm9tIHRoZSB3ZWJzaXRlcy4gSW4gYSBmaXJzdCBzdGVwLCBhIGxpc3Qgb2YgbGlua3Mgb2YgYWxsIHRoZSBzdWJwYWdlcyBvZiBhIHdlYnNpdGUgaXMgYmVpbmcgY3JlYXRlZC4gTmV4dCwgdGhpcyBsaXN0IG9mIGxpbmtzIGlzIHByb2Nlc3NlZCBhbmQgdGhlIHRleHQgZGF0YSBpcyBiZWluZyByZXRyaWV2ZWQgYW5kIHNhdmVkIGluIC50eHQgZmlsZXMuIFRoaXMgd2FzIGRvbmUgaW4gdGhlIHRlcm1pbmFsLCBub3QgaW4gUi4gCmBgYHtiYXNofQojIHJ1biBsaW5rIGRpc2NvdmVyeSB0aHJvdWdoIHdlYnNpdGUgYW5kIHN0b3JlIHRoZSByZXN1bHRpbmcgbGlua3MgaW4gYSBmaWxlCiQgdHJhZmlsYXR1cmEgLS1zaXRlbWFwICJodHRwczovL3d3dy5rbGltYXJlcG9ydGVyLmRlIiAtLWxpc3QgPiBrbGltYXJlcG9ydGVybGlua3MudHh0CgojIHRvIHByb2Nlc3MgbGlzdCBvZiBsaW5rcyBhbmQgZ2V0IHRleHRzCiQgdHJhZmlsYXR1cmEgLWkga2xpbWFyZXBvcnRlcmxpbmtzLnR4dCAtbyBrbGltYXJlcG9ydGVyX3RleHRzCmBgYAoKIyMgMi4gQ29ycHVzIENyZWF0aW9uCgojIyMgTG9hZCByZXF1aXJlZCBsaWJyYXJpZXMKYGBge3J9CiMgbG9hZCBsaWJyYXJpZXMKbGlicmFyeShxdWFudGVkYSkKbGlicmFyeShyZWFkdGV4dCkKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRtKQpsaWJyYXJ5KCJ0ZXh0Y2F0IikKbGlicmFyeSgicXVhbnRlZGEudGV4dHBsb3RzIikKbGlicmFyeSgicXVhbnRlZGEudGV4dHN0YXRzIikKbGlicmFyeSgiZ3N1YmZuIikKbGlicmFyeSgic3BhY3lyIikKbGlicmFyeShicm9vbSkKCnNwYWN5X2luaXRpYWxpemUobW9kZWwgPSAiZGVfY29yZV9uZXdzX3NtIikKYGBgCgpUbyBvcGVuIHRoZSBwcmV2aW91c2x5IGNyZWF0ZWQgdGV4dCBmaWxlcywgd2UgbmVlZCB0byBydW4gdGhlIGZvbGxvd2luZyBjb2RlOgpgYGB7cn0KIyB5b3UgY2FuIGdldCB0aGUgY3VycmVudCBkaXJlY3RvcnkgZm9yIGltcG9ydGluZyB0aGUgdGV4dCBmaWxlcyBieSBzZXR0aW5nIGN1cnJlbnQgZGlyZWN0b3J5IGFuZCBvcGVuIHJlbGF0aXZlIHBhdGggZnJvbSB0aGVyZSB3aXRoCiN0ZXh0cyA8LSByZWFkdGV4dCgicGF0aC8qIikKCiNzZXR3ZCgiL1VzZXJzL2FubmEvRG9jdW1lbnRzL3RleHRtaW5pbmcvdGV4dG1pbmluZ19jbGltYXRlIikKCiMgY2xpbWF0ZSBjaGFuZ2UgYWN0aXZpc3RzIHRleHRzCmZmZl9kZV90ZXh0cyA8LSByZWFkdGV4dCgidGV4dF9maWxlcy9wcm8vZmZmX2RlX3RleHRzLyoiKQppa2VtX3RleHRzIDwtIHJlYWR0ZXh0KCJ0ZXh0X2ZpbGVzL3Byby9pa2VtX3RleHRzLyoiKQprbGltYXJlcF90ZXh0cyA8LSByZWFkdGV4dCgidGV4dF9maWxlcy9wcm8va2xpbWFyZXBvcnRlcl90ZXh0cy8qIikKa2xpbWFmYWt0ZW5fdGV4dHMgPC0gcmVhZHRleHQoInRleHRfZmlsZXMvcHJvL2tsaW1hZmFrdGVuX3RleHRzLyoiKQp6ZXJvX3RleHRzIDwtIHJlYWR0ZXh0KCJ0ZXh0X2ZpbGVzL3Byby9nZXJtYW56ZXJvX3RleHRzLyoiKQprb21tYV90ZXh0cyA8LSByZWFkdGV4dCgidGV4dF9maWxlcy9wcm8va29tbWFfdGV4dHMvKiIpCgojIGNsaW1hdGUgY2hhbmdlIHNjZXB0aWNzIHRleHRzCmVpa2VfdGV4dHMgPC0gcmVhZHRleHQoInRleHRfZmlsZXMvY29udHJhL2Vpa2VfdGV4dHMvKiIpCmBgYAoKIyMjIEJ1aWxkaW5nIGEgQ29ycHVzCmBgYHtyfQojIGJ1aWxkIGNvcnB1cyBmb3IgZWFjaCB0ZXh0IHdpdGggIm9yaWdpbiIgdGFnCiMgc3BlY2lmeSBsYW5ndWFnZSBmb3IgZWFjaCB0ZXh0IHRvIGdldCByaWQgb2Ygbm9uLUdlcm1hbiB0ZXh0cyAKCiMgYWN0aXZpc3RzCmZmZl9kZV9jb3JwdXMgPC0gY29ycHVzKGZmZl9kZV90ZXh0cykKZG9jdmFycyhmZmZfZGVfY29ycHVzLCAib3JpZ2luIikgPC0gImZmZl9kZSIKZG9jdmFycyhmZmZfZGVfY29ycHVzLCAibGFuZ3VhZ2UiKSA8LSB0ZXh0Y2F0KGZmZl9kZV9jb3JwdXMpCmZmZl9kZV9jb3JwdXMgPC0gY29ycHVzX3N1YnNldChmZmZfZGVfY29ycHVzLCBsYW5ndWFnZSA9PSAiZ2VybWFuIiwgZHJvcF9kb2NpZCA9IFRSVUUpCgppa2VtX2NvcnB1cyA8LSBjb3JwdXMoaWtlbV90ZXh0cykKZG9jdmFycyhpa2VtX2NvcnB1cywgIm9yaWdpbiIpIDwtICJpa2VtIgpkb2N2YXJzKGlrZW1fY29ycHVzLCAibGFuZ3VhZ2UiKSA8LSB0ZXh0Y2F0KGlrZW1fY29ycHVzKQppa2VtX2NvcnB1cyA8LSBjb3JwdXNfc3Vic2V0KGlrZW1fY29ycHVzLCBsYW5ndWFnZSA9PSAiZ2VybWFuIiwgZHJvcF9kb2NpZCA9IFRSVUUpCgprbGltYXJlcF9jb3JwdXMgPC0gY29ycHVzKGtsaW1hcmVwX3RleHRzKQpkb2N2YXJzKGtsaW1hcmVwX2NvcnB1cywgIm9yaWdpbiIpIDwtICJrciIKZG9jdmFycyhrbGltYXJlcF9jb3JwdXMsICJsYW5ndWFnZSIpIDwtIHRleHRjYXQoa2xpbWFyZXBfY29ycHVzKQprbGltYXJlcF9jb3JwdXMgPC0gY29ycHVzX3N1YnNldChrbGltYXJlcF9jb3JwdXMsIGxhbmd1YWdlID09ICJnZXJtYW4iLCBkcm9wX2RvY2lkID0gVFJVRSkKCmtsaW1hZmFrdGVuX2NvcnB1cyA8LSBjb3JwdXMoa2xpbWFmYWt0ZW5fdGV4dHMpCmRvY3ZhcnMoa2xpbWFmYWt0ZW5fY29ycHVzLCAib3JpZ2luIikgPC0gImtmIgpkb2N2YXJzKGtsaW1hZmFrdGVuX2NvcnB1cywgImxhbmd1YWdlIikgPC0gdGV4dGNhdChrbGltYWZha3Rlbl9jb3JwdXMpCmtsaW1hZmFrdGVuX2NvcnB1cyA8LSBjb3JwdXNfc3Vic2V0KGtsaW1hZmFrdGVuX2NvcnB1cywgbGFuZ3VhZ2UgPT0gImdlcm1hbiIsIGRyb3BfZG9jaWQgPSBUUlVFKQoKemVyb19jb3JwdXMgPC0gY29ycHVzKHplcm9fdGV4dHMpCmRvY3ZhcnMoemVyb19jb3JwdXMsICJvcmlnaW4iKSA8LSAiemVybyIKZG9jdmFycyh6ZXJvX2NvcnB1cywgImxhbmd1YWdlIikgPC0gdGV4dGNhdCh6ZXJvX2NvcnB1cykKemVyb19jb3JwdXMgPC0gY29ycHVzX3N1YnNldCh6ZXJvX2NvcnB1cywgbGFuZ3VhZ2UgPT0gImdlcm1hbiIsIGRyb3BfZG9jaWQgPSBUUlVFKQoKa29tbWFfY29ycHVzIDwtIGNvcnB1cyhrb21tYV90ZXh0cykKZG9jdmFycyhrb21tYV9jb3JwdXMsICJvcmlnaW4iKSA8LSAiZ2siCmRvY3ZhcnMoa29tbWFfY29ycHVzLCAibGFuZ3VhZ2UiKSA8LSB0ZXh0Y2F0KGtvbW1hX2NvcnB1cykKa29tbWFfY29ycHVzIDwtIGNvcnB1c19zdWJzZXQoa29tbWFfY29ycHVzLCBsYW5ndWFnZSA9PSAiZ2VybWFuIiwgZHJvcF9kb2NpZCA9IFRSVUUpCgojIHNjZXB0aWNzCmVpa2VfY29ycHVzIDwtIGNvcnB1cyhlaWtlX3RleHRzKQpkb2N2YXJzKGVpa2VfY29ycHVzLCAib3JpZ2luIikgPC0gImVpa2UiCmRvY3ZhcnMoZWlrZV9jb3JwdXMsICJsYW5ndWFnZSIpIDwtIHRleHRjYXQoZWlrZV9jb3JwdXMpCmVpa2VfY29ycHVzIDwtIGNvcnB1c19zdWJzZXQoZWlrZV9jb3JwdXMsIGxhbmd1YWdlID09ICJnZXJtYW4iLCBkcm9wX2RvY2lkID0gVFJVRSkKCiMgYnVpbGQgYSBQUk8gY29ycHVzIGZvciBhbGwgYWN0aXZpc3RzIHRleHRzIAojIGNyZWF0ZSBhICJncm91cCIgdGFnIHdpdGggdmFsdWUgImFjdGl2aXN0cyIKcHJvX2NvcnB1cyA8LSBmZmZfZGVfY29ycHVzK2lrZW1fY29ycHVzK2tsaW1hcmVwX2NvcnB1cytrbGltYWZha3Rlbl9jb3JwdXMremVyb19jb3JwdXMra29tbWFfY29ycHVzCmRvY3ZhcnMocHJvX2NvcnB1cywgImdyb3VwIikgPC0gImFjdGl2aXN0cyIKCiMgYnVpbGQgYSBDT05UUkEgY29ycHVzIGZvciBhbGwgc2NlcHRpY3MgdGV4dHMgCiMgY3JlYXRlIGEgImdyb3VwIiB0YWcgd2l0aCB2YWx1ZSAic2NlcHRpY3MiCmNvbnRyYV9jb3JwdXMgPC0gZWlrZV9jb3JwdXMKZG9jdmFycyhjb250cmFfY29ycHVzLCAiZ3JvdXAiKSA8LSAic2NlcHRpY3MiCmBgYAoKIyMjIENyZWF0ZSBTdWJjb3Jwb3JhICgyMDAwIHRleHRzIGVhY2gpCmBgYHtyfQojIGdldCByYW5kb20gc2FtcGxlIGNvcnB1cyBmb3IgYWN0aXZpc3RzCnBybzIwMDAgPC0gY29ycHVzX3NhbXBsZShwcm9fY29ycHVzLCBzaXplID0gMjAwMCkKCiMgZ2V0IHJhbmRvbSBzYW1wbGUgY29ycHVzIGZvciBzY2VwdGljcwpjb250cmEyMDAwIDwtIGNvcnB1c19zYW1wbGUoY29udHJhX2NvcnB1cywgc2l6ZSA9IDIwMDApCgojIGNyZWF0ZSAiZnVsbCIgKGNvbWJpbmVkKSBjb3JwdXMgd2l0aCBwcm8gYW5kIGNvbnRyYSBzYW1wbGUgCmZ1bGxfY29ycHVzIDwtIHBybzIwMDArY29udHJhMjAwMAoKIyBnZXQgaWQgbnVtYmVyIGZvciBjb3JwdXMKZG9jdmFycyhwcm8yMDAwLCAiaWQiKSA8LSBwYXN0ZSgxOm5kb2MocHJvMjAwMCkpCmRvY3ZhcnMoY29udHJhMjAwMCwgImlkIikgPC0gcGFzdGUoMTpuZG9jKGNvbnRyYTIwMDApKQpgYGAKCiMjIyBTYXZlIGNvcnB1cyBmaWxlcyBpbiAucmRzIGZvcm1hdApgYGB7cn0KIyBzYXZlIGNvcnB1cyBmaWxlcyBhcyAucmRzIGZpbGUgZm9yIGxhdGVyIHVzZQpzYXZlUkRTKGZ1bGxfY29ycHVzLCAiY29ycG9yYS9mdWxsX2NvcnB1cy5yZHMiKQoKc2F2ZVJEUyhwcm9fY29ycHVzLCAiY29ycG9yYS9wcm9fY29ycHVzLnJkcyIpCnNhdmVSRFMoY29udHJhX2NvcnB1cywgImNvcnBvcmEvY29udHJhX2NvcnB1cy5yZHMiKQoKc2F2ZVJEUyhwcm8yMDAwLCAiY29ycG9yYS9wcm8yMDAwLnJkcyIpCnNhdmVSRFMoY29udHJhMjAwMCwgImNvcnBvcmEvY29udHJhMjAwMC5yZHMiKQoKIyBhY3RpdmlzdHMKc2F2ZVJEUyhmZmZfZGVfY29ycHVzLCAiY29ycG9yYS9mZmZfZGVfY29ycHVzLnJkcyIpCnNhdmVSRFMoaWtlbV9jb3JwdXMsICJjb3Jwb3JhL2lrZW1fY29ycHVzLnJkcyIpCnNhdmVSRFMoa2xpbWFyZXBfY29ycHVzLCAiY29ycG9yYS9rbGltYXJlcF9jb3JwdXMucmRzIikKc2F2ZVJEUyhrbGltYWZha3Rlbl9jb3JwdXMsICJjb3Jwb3JhL2tsaW1hZmFrdGVuX2NvcnB1cy5yZHMiKQpzYXZlUkRTKHplcm9fY29ycHVzLCAiY29ycG9yYS96ZXJvX2NvcnB1cy5yZHMiKQpzYXZlUkRTKGtvbW1hX2NvcnB1cywgImNvcnBvcmEva29tbWFfY29ycHVzLnJkcyIpCgojIHNjZXB0aWNzCnNhdmVSRFMoZWlrZV9jb3JwdXMsICJjb3Jwb3JhL2Vpa2VfY29ycHVzLnJkcyIpCmBgYAoKIyMgMy4gQ29ycHVzIFN0YXRpc3RpY3MKCiMjIyBMb2FkIGV4aXN0aW5nIGNvcnB1cyBmaWxlcwpgYGB7cn0KIyBsb2FkIGNvcnB1cyBmaWxlcyAKZnVsbF9jb3JwdXMgPSByZWFkUkRTKCJjb3Jwb3JhL2Z1bGxfY29ycHVzLnJkcyIpCgpwcm9fY29ycHVzID0gcmVhZFJEUygiY29ycG9yYS9wcm9fY29ycHVzLnJkcyIpCmNvbnRyYV9jb3JwdXMgPSByZWFkUkRTKCJjb3Jwb3JhL2NvbnRyYV9jb3JwdXMucmRzIikKCnBybzIwMDAgPSByZWFkUkRTKCJjb3Jwb3JhL3BybzIwMDAucmRzIikKY29udHJhMjAwMCA9IHJlYWRSRFMoImNvcnBvcmEvY29udHJhMjAwMC5yZHMiKQoKIyBvcHRpb25hbDogbG9hZCAKZmZmX2RlX2NvcnB1cyA9IHJlYWRSRFMoImNvcnBvcmEvZmZmX2RlX2NvcnB1cy5yZHMiKQppa2VtX2NvcnB1cyA9IHJlYWRSRFMoImNvcnBvcmEvaWtlbV9jb3JwdXMucmRzIikKa2xpbWFyZXBfY29ycHVzID0gcmVhZFJEUygiY29ycG9yYS9rbGltYXJlcF9jb3JwdXMucmRzIikKa2xpbWFmYWt0ZW5fY29ycHVzID0gcmVhZFJEUygiY29ycG9yYS9rbGltYWZha3Rlbl9jb3JwdXMucmRzIikKemVyb19jb3JwdXMgPSByZWFkUkRTKCJjb3Jwb3JhL3plcm9fY29ycHVzLnJkcyIpCmtvbW1hX2NvcnB1cyA9IHJlYWRSRFMoImNvcnBvcmEva29tbWFfY29ycHVzLnJkcyIpCmVpa2VfY29ycHVzID0gcmVhZFJEUygiY29ycG9yYS9laWtlX2NvcnB1cy5yZHMiKQpgYGAKCiMjIyBFeHBsb3JpbmcgdGhlIGNvcnB1cwpGaXJzdCwgd2Ugd2FudCB0byBoYXZlIGEgbG9vayBhdCB0aGUgaW5mb3JtYXRpb24gZWFjaCBvZiB0aGUgY29ycG9yYSBnaXZlcyB1czoKLSB0eXBlcwotIHRva2VucwotIG51bWJlciBvZiBzZW50ZW5jZXMKLSBvcmlnaW4KLSBsYW5ndWFnZQotIGdyb3VwCi0gaWQgCgpgYGB7cn0KIyByZXRyaWV2ZSBvdmVydmlldyBvZiBjb3JwdXMgaW5mb3JtYXRpb24Kc3VtbWFyeShwcm8yMDAwLCBuID0gMTApCnN1bW1hcnkoY29udHJhMjAwMCwgbj0xMCkKYGBgCiMjIyBQbG90dGluZyBOdW1iZXIgb2YgU2VudGVuY2VzClRoZSBvdmVydmlldyBvZiB0aGUgY29ycHVzIGluZm9ybWF0aW9uIHJldmVhbHMgdGhhdCB0aGUgc2NlcHRpY3MgY29ycHVzIG1heSBjb25zaXN0IG9mIG11Y2ggbG9uZ2VyIHRleHRzIChzZWUgIlNlbnRlbmNlcyIgY291bnRzKSB0aGFuIHRoZSBhY3RpdmlzdHMgY29ycHVzLiBXZSB3YW50IHRvIHJlLWNoZWNrIHRoaXMgaW5mb3JtYXRpb24gYnkgcGxvdHRpbmcgdGhlIHNlbnRlbmNlcyBjb3V0bnMgZm9yIGEgc3Vic2V0IG9mIHRoZSBkYXRhLiAKYGBge3J9CiMgcmV0cmlldmUgY29ycHVzIGluZm9ybWF0aW9uIChzYW1wbGUgb2YgNTAgZW50cmllcykKY29udHJhMjAwMF9zdW0gPC0gc3VtbWFyeShjb250cmEyMDAwLCBuPTUwKQpwcm8yMDAwX3N1bSA8LSBzdW1tYXJ5KHBybzIwMDAsIG49NTApCgojIGNyZWF0ZSBwbG90cyBmcm9tIGNvcnB1cyBpbmZvcm1hdGlvbgpnZ3Bsb3QocHJvMjAwMF9zdW0sIGFlcyhpZCwgU2VudGVuY2VzLCBncm91cD0xKSkgKwogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0wLCB2anVzdD0xLCBoanVzdD0xKSkgKyAKICBnZ3RpdGxlKCJTZW50ZW5jZXMgUHJvMjAwMCIpCgpnZ3Bsb3QoY29udHJhMjAwMF9zdW0sIGFlcyhpZCwgU2VudGVuY2VzLCBncm91cD0xKSkgKwogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0wLCB2anVzdD0xLCBoanVzdD0xKSkgKyAKICBnZ3RpdGxlKCJTZW50ZW5jZXMgQ29udHJhMjAwMCIpCgpgYGAKTm93IHdlIGNhbiBjYWx1Y3VsYXRlIHRoZSBtZWFuIGNvdW50IG9mIHRoZSBzZW50ZW5jZXMgYnkgcnVubmluZyB0aGUgZm9sbG93aW5nIGNvZGUuCmBgYHtyfQojIGdldCBtZWFuIG9mIHNlbnRlbmNlcyBjb3VudCBmb3IgYWN0aXZpdHN0CnNlbnRzX3BybyA9IHN1bW1hcnkocHJvMjAwMCwgbj1uZG9jKHBybzIwMDApKSRTZW50ZW5jZXMKbWVhbihzZW50c19wcm8pCgojIGdldCBtZWFuIG9mIHNlbnRlbmNlcyBjb3VudCBmb3Igc2NlcHRpY3MKc2VudHNfY29uID0gc3VtbWFyeShjb250cmEyMDAwLCBuPW5kb2MoY29udHJhMjAwMCkpJFNlbnRlbmNlcwptZWFuKHNlbnRzX2NvbikKYGBgCgpUaGUgcmVzdWx0cyBzaG93LCB0aGF0IHRoZSB0ZXh0cyBvZiB0aGUgYWN0aXZpc3RzIGNvcnB1cyBjb25zaXN0IG9mIGF2ZXJhZ2VseSAyNCw3IHNlbnRlbmNlcywgbWVhbndoaWxlIHRoZSB0ZXh0cyBvZiB0aGUgc2NlcHRpY3MgY29ycHVzIGhhdmUgYW4gYXZlcmFnZSBudW1iZXIgb2Ygc2VudGVuY2VzIG9mIDczLDguIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgdGV4dHMgb2YgdGhlIHNjZXB0aWNzIGNvcnB1cyBhcmUgbXVjaCBsb25nZXIgdGhhbiB0aGUgb25lcyBpbiB0aGUgb3RoZXIgY29ycHVzLiAKCiMjIyBUeXBlLVRva2VuIFJhdGlvIChUVFIpCk5vdyBsZXQncyBoYXZlIGEgbG9vayBhdCB0aGUgVFRSIG9mIGJvdGggY29ycG9yYS4KYGBge3J9CiMgcmV0cmlldmUgVFRSIGZvciBwcm8gY29ycHVzCnR0cl9wMjAwMCA8LSB0ZXh0c3RhdF9sZXhkaXYoZGZtX3AyMDAwLCBtZWFzdXJlID0iVFRSIiwgcmVvdmVfbnVtYmVycyA9IFRSVUUsIHJlbW92ZV9wdW5jdCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9zeW1ib2xzID0gVFJVRSkKCiMgZ2V0IG1lYW4gdmFsdWUKbWVhbih0dHJfcDIwMDAkVFRSKQoKIyByZXRyaWV2ZSBUVFIgZm9yIGNvbnRyYSBjb3JwdXMKdHRyX2MyMDAwIDwtIHRleHRzdGF0X2xleGRpdihkZm1fYzIwMDAsIG1lYXN1cmUgPSJUVFIiLCByZW92ZV9udW1iZXJzID0gVFJVRSwgcmVtb3ZlX3B1bmN0ID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX3N5bWJvbHMgPSBUUlVFKQoKIyBnZXQgbWVhbiB2YWx1ZQptZWFuKHR0cl9jMjAwMCRUVFIpCgpgYGAKClRoZSBjbG9zZXIgdGhlIHZhbHVlIGFwcHJveGltYXRlcyB0byAxLCB0aGUgZ3JlYXRlciB0aGUgbGV4aWNhbCByaWNobmVzcy4gQm90aCBjb3Jwb3JhIGFwcGVhciB0byBoYXZlIHZlcnkgc2ltaWxhciBUVFJzIGFuZCB0aHVzIHNlZW0gdG8gcmV2ZWFsIHZlcnkgc2ltaWxhciBsZXhpY2FsIHJpY2huZXNzIG9mIHRoZSB0ZXh0cy4gCgojIyA0LiBFbXBpcmljYWwgV29yawoKIyMjIENyZWF0ZSBhIERvY3VtZW50LUZlYXR1cmUgTWF0cml4IChkZm0pLCBsb2FkIHN0b3AgbGlzdHMgCmBgYHtyfQojIHJldHJpZXZlIHN0b3BsaXN0cwpkZV9zdG9wd29yZHMgPC0gc3RvcHdvcmRzOjpzdG9wd29yZHMoImRlIiwgc291cmNlPSJzbm93YmFsbCIpCmVuX3N0b3B3b3JkcyA8LSBzdG9wd29yZHM6OnN0b3B3b3JkcygiZW4iLCBzb3VyY2U9InNub3diYWxsIiApCmN1c3RvbV9zdG9wd29yZHMgPC0gcmVhZC50YWJsZSgiZGVfY29tcGxldGUudHh0IiwgaGVhZGVyPUYsIHNlcD0iXG4iKQoKIyBhZGQgb3duIHN0b3B3b3JkcyAKZnVsbF9zdG9wd29yZHMgPC0gYyhkZV9zdG9wd29yZHMsICJkYXNzIiwgIj0iLCAidGhlIiwgInNlaXQiLCAiYWIiLCAiYmVpbSIsICJcbiIsICJtYWwiLCAiYyIsICJ8IiwgIm0iLCAia29tbWVudGFyZSIsICJuZXVlc3RlIiwgImdlcG9zdGV0IiwgY3VzdG9tX3N0b3B3b3JkcywgZW5fc3RvcHdvcmRzKQpkZV9zdG9wd29yZHMxIDwtIGMoZGVfc3RvcHdvcmRzLCAiZGFzcyIsICI9IiwgInRoZSIsICJzZWl0IiwgImFiIiwgImJlaW0iLCAiXG4iLCAibWFsIiwgImMiLCAiXFx8IiwifCIsICJtIiwgImtvbW1lbnRhcmUiLCAibmV1ZXN0ZSIsICJnZXBvc3RldCIsICJhZG1pbiIsICJjb29raWVzIiwgImluaGFsdGUiLCAiaW5oYWx0IiwgIm5ld3NsZXR0ZXIiLCAicG9zdGVuIiwgInp1Z3JpZmYiLCAicGFzc3dvcnQiLCAiZ2VzY2jDvHR6dCIsICJzZWl0ZSIsICJ3ZWJzaXRlIiwgIndlYnNlaXRlIiwgImFuZCIsICIwIiwgIjEiLCAiMiIsICIzIiwiNCIsIjUiLCI2IiwiNyIsIjgiLCI5IiwgIm1mZyIsInciLCJ0Iiwid2VyIikKCgojIGNyZWF0ZSBkZm0KZGZtX3AyMDAwIDwtIGRmbShwcm8yMDAwLCByZW1vdmU9ZnVsbF9zdG9wd29yZHMsIHJlbW92ZV9wdW5jdD1UUlVFLCByZW1vdmVfbnVtYmVycz1UUlVFLCB0b2xvd2VyPVRSVUUpCmRmbV9jMjAwMCA8LSBkZm0oY29udHJhMjAwMCwgcmVtb3ZlPWZ1bGxfc3RvcHdvcmRzLCByZW1vdmVfcHVuY3Q9VFJVRSwgcmVtb3ZlX251bWJlcnM9VFJVRSwgdG9sb3dlcj1UUlVFKQpgYGAKCkxldCdzIGhhdmUgYSBsb29rIGF0IHRoZSBkZm0gb2YgYm90aCBjb3Jwb3JhOgpgYGB7cn0KIyBwcm8gY29ycHVzIGRmbQpkZm1fcDIwMDAKYGBgCmBgYHtyfQojIGNvbnRyYSBjb3JwdXMgZGZtCmRmbV9jMjAwMApgYGAKVGhlIGRvY3VtZW50LWZlYXR1cmUgbWF0cml4IGJhc2ljYWxseSBjb25zaXN0cyBvZiByb3dzIGZvciBlYWNoIHRleHQgYW5kIGNvbHVtbnMgZm9yIGVhY2ggd29yZCBpbiB0aGUgdGV4dHMuIFRoZSBjb2x1bW4gdmFsdWVzIHJlZmxlY3QgaG93IG1hbnkgdGltZXMgYSB0ZXJtIGFwcGVhcnMgaW4gYSB0ZXh0IC0gaWYgYSB0ZXJtIGRvZXMgbm90IG9jY3VyIGluIGEgdGV4dCwgaXRzIHZhbHVlIGlzIHplcm8uIAoKIyMjIENvcnB1cyBDbGVhbmluZwpUbyBjbGVhbiB0aGUgY29ycG9yYSBsZW1tYXRpemF0aW9uIGFuZCBhcHBsaWNhdGlvbiBvZiBzdG9wIGxpc3RzIChzZWUgcHJldmlvdXMgc3RlcCkgd2FzIHBlcmZvcm1lZC4gRm9yIHRoZSBsZW1tYXRpemF0aW9uLCB0aGUgc3BhY3lyIGxpYnJhcnkgd2FzIHVzZWQuIAoKSW5mbzogVGhpcyBwaWVjZSBvZiBjb2RlIHRha2VzIHNvbWUgdGltZSB0byBydW4uIApgYGB7cn0KIyBwYXJzZSB0aGUgcHJvIGNvcnB1cyB3aXRoIHNwYWN5IGZ1bmN0aW9uIGFuZCByZXRyaWV2ZSBsZW1tYSBmb3IgZWFjaCB0b2tlbgpzcF9wcm8yMDAwIDwtIHNwYWN5X3BhcnNlKHBybzIwMDAsIHBvcz1GQUxTRSwgZW50aXR5PUZBTFNFLCBkZXBlbmRlbmN5PUZBTFNFKQpzcF9wcm8yMDAwJHRva2VuIDwtIHNwX3BybzIwMDAkbGVtbWEKCiMgY3JlYXRlIGxlbW1hdGl6ZWQgdmVyc2lvbiBvZiBkZm0gZm9yIGFjdGl2aXN0cyBjb3JwdXMKc3BfZGZtX3AyMDAwIDwtIGFzLnRva2VucyhzcF9wcm8yMDAwKSU+JQogIGRmbShyZW1vdmU9ZnVsbF9zdG9wd29yZHMsIHJlbW92ZV9wdW5jdD1UUlVFLCByZW1vdmVfbnVtYmVycz1UUlVFLCB0b2xvd2VyPVRSVUUpCgojIHBhcnNlIHRoZSBjb250cmEgY29ycHVzIHdpdGggc3BhY3kgZnVuY3Rpb24gYW5kIHJldHJpZXZlIGxlbW1hIGZvciBlYWNoIHRva2VuCnNwX2NvbnRyYTIwMDAgPC0gc3BhY3lfcGFyc2UoY29udHJhMjAwMCwgcG9zPUZBTFNFLCBlbnRpdHk9RkFMU0UsIGRlcGVuZGVuY3k9RkFMU0UpCnNwX2NvbnRyYTIwMDAkdG9rZW4gPC0gc3BfY29udHJhMjAwMCRsZW1tYQoKIyBjcmVhdGUgbGVtbWF0aXplZCB2ZXJzaW9uIG9mIGRmbSBmb3Igc2NlcHRpY3MgY29ycHVzCnNwX2RmbV9jMjAwMCA8LSBhcy50b2tlbnMoc3BfY29udHJhMjAwMCklPiUKICBkZm0ocmVtb3ZlPWZ1bGxfc3RvcHdvcmRzLCByZW1vdmVfcHVuY3Q9VFJVRSwgcmVtb3ZlX251bWJlcnM9VFJVRSwgdG9sb3dlcj1UUlVFKQpgYGAKCmBgYHtyfQojIHBhcnNlIHRoZSBmdWxsIGNvcnB1cyB3aXRoIHNwYWN5IGZ1bmN0aW9uIGFuZCByZXRyaWV2ZSBsZW1tYSBmb3IgZWFjaCB0b2tlbgpzcF9mdWxsIDwtIHNwYWN5X3BhcnNlKGZ1bGxfY29ycHVzLCBwb3M9RkFMU0UsIGVudGl0eT1GQUxTRSwgZGVwZW5kZW5jeT1GQUxTRSkKc3BfZnVsbCR0b2tlbiA8LSBzcF9mdWxsJGxlbW1hCgojIGNyZWF0ZSBsZW1tYXRpemVkIHZlcnNpb24gb2YgZGZtIGZvciBzY2VwdGljcyBjb3JwdXMKc3BfZGZtX2Z1bGwgPC0gYXMudG9rZW5zKHNwX2Z1bGwpICU+JQogIGRmbShyZW1vdmU9ZnVsbF9zdG9wd29yZHMsIHJlbW92ZV9wdW5jdD1UUlVFLCByZW1vdmVfbnVtYmVycz1UUlVFLCB0b2xvd2VyPVRSVUUpCmBgYAoKQ29tbWVudDogVGhlIEdlcm1hbiBsZW1tYXRpemF0aW9uIHdpdGggc3BhY3lyIGlzIG5vdCB2ZXJ5IGFjY3VyYXRlLiBBIGxvdCBvZiBjb21wb3VuZHMgZG8gbm90IGdldCBsZW1tYXRpemVkIGF0IGFsbCBhbmQgdGhlcmVmb3JlIGFwcGVhciBtdWx0aXBsZSB0aW1lcyAoaW4gYWxsIHBvc3NpYmxlIGZvcm1zKSBpbiB0aGUgZGZtLiAKCiMjIyBNb3N0IGZyZXF1ZW50IHRlcm1zCldpdGggdGhlIGhlbHAgb2YgwrR0b3BmZWF0dXJlc8K0IHdlIGNhbiBjaGVjayB0aGUgbW9zdCBmcmVxdWVudGx5IG9jY3VyaW5nIHRlcm1zIGZvciBlYWNoIGRmbS4KYGBge3J9CiMgY2hlY2sgdG9wIDUwIHRlcm1zIGZvciBhY3RpdmlzdHMgY29ycHVzCnRvcGZlYXR1cmVzKHNwX2RmbV9wMjAwMCwgbj01MCkKYGBgCgpgYGB7cn0KIyBjaGVjayB0b3AgNTAgdGVybXMgZm9yIHNjZXB0aWNzIGNvcnB1cyAKdG9wZmVhdHVyZXMoc3BfZGZtX2MyMDAwLCBuPTUwKQpgYGAKU2luY2UgdGhvc2UgbGlzdHMgYXJlIG5vdCBlYXN5IHRvIGhhbmRsZSwgd2Ugd2lsbCBjcmVhdGUgYSBwbG90IG9mIHRoZSBpbmZvcm1hdGlvbiBpbiB0aGUgZm9sbG93aW5nIHNlY3Rpb25zLiAKCiMjIFBsb3R0aW5nIEZyZXF1ZW5jaWVzClRvIHBsb3QgdGhlIG1vc3QgZnJlcXVlbnQgd29yZHMgb2YgZWFjaCBjb3JwdXMsIGxldCdzIHJ1biB0aGUgZm9sbG93aW5nIGNvZGU6CmBgYHtyfQojIGdldCBmcmVxdWVuY2llcyBvZiBhIHNhbXBsZSBvZiA1MCB3b3JkcyBmcm9tIHRoZSBjb3Jwb3JhCmZyZXFfcDIwMDAgPC0gdGV4dHN0YXRfZnJlcXVlbmN5KHNwX2RmbV9wMjAwMCwgbj01MCkKZnJlcV9jMjAwMCA8LSB0ZXh0c3RhdF9mcmVxdWVuY3koc3BfZGZtX2MyMDAwLCBuPTUwKQoKIyBjcmVhdGUgZnJlcXVlbmN5IHBsb3RzCnBsb3RfcDIwMDAkZmVhdHVyZSA8LSB3aXRoKGZyZXFfcDIwMDAsIHJlb3JkZXIoZmVhdHVyZSwgLWZyZXF1ZW5jeSkpCnBsb3RfYzIwMDAkZmVhdHVyZSA8LSB3aXRoKGZyZXFfYzIwMDAsIHJlb3JkZXIoZmVhdHVyZSwgLWZyZXF1ZW5jeSkpCgojIGNyZWF0ZSBwbG90IGZvciBhY3RpdmlzdHMgY29ycHVzIHdvcmQgZnJlcXVlbmNpZXMKcGxvdDEgPC0gZ2dwbG90KGZyZXFfcDIwMDAsIGFlcyh4PWZlYXR1cmUsIHk9ZnJlcXVlbmN5KSkgKyAKICBnZW9tX3BvaW50KCkrZ2d0aXRsZSgiUDIwMDAgRnJlcXVlbmNpZXMiKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xKSkKcGxvdDEKCiMgY3JlYXRlIHBsb3QgZm9yIHNjZXB0aWNzIGNvcnB1cyB3b3JkIGZyZXF1ZW5jaWVzCnBsb3QyIDwtIGdncGxvdChmcmVxX2MyMDAwLCBhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludCgpKyBnZ3RpdGxlKCJDMjAwMCBGcmVxdWVuY2llcyIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTEpKSAKcGxvdDIKYGBgCgpUaGlzIGFscmVhZHkgZ2l2ZXMgdXMgYSBmaXJzdCBpbXByZXNzaW9uIG9mIHRoZSBjb250ZW50IG9mIHRoZSBjb3Jwb3JhIHRleHRzLiAKCk5ldmVydGhlbGVzcywgd2UgYXJlIHBhcnRpY3VsYXJseSBpbnRlcmVzdGVkIGluIHRoZSB3b3JkIGZyZXF1ZW5jaWVzIG9mIEdlcm1hbiBjbGltYXRlIGNoYW5nZSBjb21wb3VuZCBub3Vucy4gQWNjb3JkaW5nbHksIHdlIHN0YXJ0IHdpdGggdGhlIHJldHJpZXZhbCBvZiB0ZXJtcyBzdGFydGluZyB3aXRoICJrbGltYSIgdG8gaG9wZWZ1bGx5IGdldCBzb21lIGNsaW1hdGUgY2hhbmdlIGNvbXBvdW5kcy4gSW4gdGhlIGVueHQgc3RlcCwgYWdhaW4gd2UgcmV0cmlldmUgdGhlIGZyZXF1ZW5jaWVzIG9mIHRoZSB3b3JkcyBhbmQgY3JlYXRlIHBsb3RzIGZvciBib3RoIGNvcnBvcmEuIApgYGB7cn0KIyBjcmVhdGUgYSBzYW1wbGUgb2YgdGhlIGRmbSB3aXRoIGFsbCB3b3JkcyBzdGFydGluZyB3aXRoICJrbGltYS4uLiIgCmtsaW1hX3AyMDAwIDwtIGRmbV9zZWxlY3Qoc3BfZGZtX3AyMDAwLCBwYXR0ZXJuPSJrbGltYSoiKQprbGltYV9jMjAwMCA8LSBkZm1fc2VsZWN0KHNwX2RmbV9jMjAwMCwgcGF0dGVybj0ia2xpbWEqIikKCiMgcmV0cmlldmUgZnJlcXVlbmNpZXMgZm9yIGEgc2FtcGxlIG9mIDUwIHdvcmRzIApmcmVxX2tsaW1hX3AyMDAwIDwtIHRleHRzdGF0X2ZyZXF1ZW5jeShrbGltYV9wMjAwMCwgbj01MCkKZnJlcV9rbGltYV9jMjAwMCA8LSB0ZXh0c3RhdF9mcmVxdWVuY3koa2xpbWFfYzIwMDAsIG49NTApCgojIGNyZWF0ZSBmcmVxdWVuY3kgcGxvdHMgZm9yICJrbGltYSIgd29yZHMKZnJlcV9rbGltYV9wMjAwMCRmZWF0dXJlIDwtIHdpdGgoZnJlcV9rbGltYV9wMjAwMCwgcmVvcmRlcihmZWF0dXJlLCAtZnJlcXVlbmN5KSkKZnJlcV9rbGltYV9jMjAwMCRmZWF0dXJlIDwtIHdpdGgoZnJlcV9rbGltYV9jMjAwMCwgcmVvcmRlcihmZWF0dXJlLCAtZnJlcXVlbmN5KSkKCiMgY3JlYXRlIHBsb3QgZm9yIGFjdGl2aXN0cyBjb3JwdXMgImtsaW1hIiB3b3JkIGZyZXF1ZW5jaWVzCnBsb3QzIDwtIGdncGxvdChmcmVxX2tsaW1hX3AyMDAwLCBhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludCgpK2dndGl0bGUoIlAyMDAwICdLbGltYScgV29yZCBGcmVxdWVuY2llcyIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTEpKQpwbG90MwoKIyBjcmVhdGUgcGxvdCBmb3Igc2NwZXRpY3MgY29ycHVzICJrbGltYSIgd29yZCBmcmVxdWVuY2llcwpwbG90NCA8LSBnZ3Bsb3QoZnJlcV9rbGltYV9jMjAwMCwgYWVzKHg9ZmVhdHVyZSwgeT1mcmVxdWVuY3kpKSArIAogIGdlb21fcG9pbnQoKSsgZ2d0aXRsZSgiQzIwMDAgJ0tsaW1hJyBXb3JkIEZyZXF1ZW5jaWVzIikrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MSkpIApwbG90NAoKYGBgCkluIHRoZSBmb2xsb3dpbmcgc3RlcCB3ZSByZXRyaWV2ZSBsaXN0cyBvZiB0aGUgdGVybXMgd2hpY2ggb25seSBhcHBlYXIgaW4gb25lIG9mIHRoZSBUb3A1MCBsaXN0cy4gCkZvciBhY3RpdmlzdHMgZ3JvdXA6CmBgYHtyfQojIGdldCBsaXN0IG9mIGNsaW1hdGUgY2hhbmdlIGNvbXBvdW5kcyBvbmx5IGFwcGVhcmluZyBpbiB0b3A1MCBmb3IgYWN0aXZpc3RzIApzZXRkaWZmKGZyZXFfa2xpbWFfcDIwMDAkZmVhdHVyZSwgZnJlcV9rbGltYV9jMjAwMCRmZWF0dXJlKQpgYGAKRm9yIHNjZXB0aWNzIGdyb3VwOgpgYGB7cn0KIyBnZXQgbGlzdCBvZiBjbGltYXRlIGNoYW5nZSBjb21wb3VuZHMgb25seSBhcHBlYXJpbmcgaW4gdG9wNTAgZm9yIGFjdGl2aXN0cyAKc2V0ZGlmZihmcmVxX2tsaW1hX2MyMDAwJGZlYXR1cmUsIGZyZXFfa2xpbWFfcDIwMDAkZmVhdHVyZSkKYGBgCiMjIyBURi1JREYKVG8gZ2V0IHdlaWdodGVkIGZyZXF1ZW5jaWVzIG9mIHRoZSBjb3Jwb3JhLCBpdCBpcyBuZWNlc3NhcnkgdG8gaGF2ZSBhIGxvb2sgYXQgdGhlIHRmLWlkZiAodGVybSBmcmVxdWVuY3ktaW52ZXJzZSBkb2N1bWVudCBmcmVxZXVuY3kpIG9mIHRoZSB3b3Jkcy4gCmBgYHtyfQojIHdlaWdodGVkIHdvcmRzCnAyMDAwX3dlaWdodCA8LSBkZm1fd2VpZ2h0KHNwX2RmbV9wMjAwMCwgc2NoZW1lPSJwcm9wIikKYzIwMDBfd2VpZ2h0IDwtIGRmbV93ZWlnaHQoc3BfZGZtX2MyMDAwLCBzY2hlbWU9InByb3AiKQoKcmVsZnJlcV9wMjAwMCA8LSB0ZXh0c3RhdF9mcmVxdWVuY3kocDIwMDBfd2VpZ2h0LCBuPTUwKQpyZWxmcmVxX2MyMDAwIDwtIHRleHRzdGF0X2ZyZXF1ZW5jeShjMjAwMF93ZWlnaHQsIG49NTApCgojdGZpZGYKcDIwMDBfdGZpZGYgPC0gZGZtX3RmaWRmKHNwX2RmbV9wMjAwMCwgc2NoZW1lX3RmID0gInByb3AiLCBzY2hlbWVfZGYgPSAiaW52ZXJzZSIpCmMyMDAwX3RmaWRmIDwtIGRmbV90ZmlkZihzcF9kZm1fYzIwMDAsIHNjaGVtZV90ZiA9ICJwcm9wIiwgc2NoZW1lX2RmID0gImludmVyc2UiKQoKI3Bsb3QzIDwtIHdpdGgocmVsZnJlcV9wMjAwMCwgcmVvcmRlcihmZWF0dXJlLCAtZnJlcWVuY3kpKQpyZWxmcmVxX3AyMDAwJGZlYXR1cmUgPC0gd2l0aChyZWxmcmVxX3AyMDAwLCByZW9yZGVyKGZlYXR1cmUsIC1mcmVxdWVuY3kpKQpwbG90MyA8LSBnZ3Bsb3QocmVsZnJlcV9wMjAwMCwgYWVzKHg9ZmVhdHVyZSwgeT1mcmVxdWVuY3kpKSArIAogIGdlb21fcG9pbnQoKStnZ3RpdGxlKCJQMjAwMCBGcmVxdWVuY2llcyIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTEpKQojZ2dzYXZlKHBsb3Q9cGxvdDEsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIGRwaT0zMDAsIGZpbGVuYW1lPSJrbGltYV9laWtlX3Bsb3QuanBlZyIgKQpwbG90MwoKYGBgCmBgYHtyfQojIHdlaWdodGVkIHdvcmRzCnAyMDAwX2tsaW1hX3dlaWdodCA8LSBkZm1fd2VpZ2h0KGtsaW1hX3AyMDAwLCBzY2hlbWU9InByb3AiKQpjMjAwMF9rbGltYV93ZWlnaHQgPC0gZGZtX3dlaWdodChrbGltYV9jMjAwMCwgc2NoZW1lPSJwcm9wIikKCnJlbGZyZXFfcDIwMDAgPC0gdGV4dHN0YXRfZnJlcXVlbmN5KHAyMDAwX2tsaW1hX3dlaWdodCwgbj01MCkKcmVsZnJlcV9jMjAwMCA8LSB0ZXh0c3RhdF9mcmVxdWVuY3koYzIwMDBfa2xpbWFfd2VpZ2h0LCBuPTUwKQoKI3RmaWRmCnAyMDAwX3RmaWRmIDwtIGRmbV90ZmlkZihzcF9kZm1fcDIwMDAsIHNjaGVtZV90ZiA9ICJwcm9wIiwgc2NoZW1lX2RmID0gImludmVyc2UiKQpjMjAwMF90ZmlkZiA8LSBkZm1fdGZpZGYoc3BfZGZtX2MyMDAwLCBzY2hlbWVfdGYgPSAicHJvcCIsIHNjaGVtZV9kZiA9ICJpbnZlcnNlIikKCnJlbGZyZXFfcDIwMDAkZmVhdHVyZSA8LSB3aXRoKHJlbGZyZXFfcDIwMDAsIHJlb3JkZXIoZmVhdHVyZSwgLWZyZXF1ZW5jeSkpCnBsb3Q3IDwtIGdncGxvdChyZWxmcmVxX3AyMDAwLCBhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludCgpK2dndGl0bGUoIlAyMDAwIEtsaW1hIFdvcmRzIC0gUmVsYXRpdmUgRnJlcXVlbmNpZXMiKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xKSkKcGxvdDcKCnJlbGZyZXFfYzIwMDAkZmVhdHVyZSA8LSB3aXRoKHJlbGZyZXFfYzIwMDAsIHJlb3JkZXIoZmVhdHVyZSwgLWZyZXF1ZW5jeSkpCnBsb3Q4IDwtIGdncGxvdChyZWxmcmVxX2MyMDAwLCBhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeSkpICsgCiAgZ2VvbV9wb2ludCgpK2dndGl0bGUoIkMyMDAwIEtsaW1hIFdvcmRzIC0gUmVsYXRpdmUgRnJlcXVlbmNpZXMiKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCxoanVzdD0xKSkKcGxvdDgKCmBgYApgYGB7cn0KcDIwMDBfdGZpZGYgPC0gZGZtX3RmaWRmKGtsaW1hX3AyMDAwLCBzY2hlbWVfdGYgPSAicHJvcCIsIHNjaGVtZV9kZiA9ICJpbnZlcnNlIikKYzIwMDBfdGZpZGYgPC0gZGZtX3RmaWRmKGtsaW1hX2MyMDAwLCBzY2hlbWVfdGYgPSAicHJvcCIsIHNjaGVtZV9kZiA9ICJpbnZlcnNlIikKCgpwcm9fZnJlcV90ZmlkZiA8LSBwMjAwMF90ZmlkZiAlPiUKICB0ZXh0c3RhdF9mcmVxdWVuY3kobj0yMCwgZm9yY2U9VFJVRSkKCmNvbl9mcmVxX3RmaWRmIDwtIGMyMDAwX3RmaWRmICU+JQogIHRleHRzdGF0X2ZyZXF1ZW5jeShuPTIwLCBmb3JjZT1UUlVFKQoKdHBsb3RfdGZpZGZfcDIwMDAgPC0gZ2dwbG90KGRhdGE9cHJvX2ZyZXFfdGZpZGYsCiAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1mYWN0b3IobnJvdyhwcm9fZnJlcV90ZmlkZik6MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1mcmVxdWVuY3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJQMjAwMCAnS2xpbWEnIFdvcmRzIC0gUmVsYXRpdmUgRnJlcXVlbmNpZXMiKSsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzPWZhY3Rvcihucm93KHByb19mcmVxX3RmaWRmKToxKSwKICAgICAgICAgICAgICAgICAgIGxhYmVscz1wcm9fZnJlcV90ZmlkZiRmZWF0dXJlKSArCiAgbGFicyh4PU5VTEwsIHk9InRmLWlkZiIpCgp0cGxvdF90ZmlkZl9wMjAwMAoKdHBsb3RfdGZpZGZfYzIwMDAgPC0gZ2dwbG90KGRhdGE9Y29uX2ZyZXFfdGZpZGYsCiAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1mYWN0b3IobnJvdyhjb25fZnJlcV90ZmlkZik6MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1mcmVxdWVuY3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZ3RpdGxlKCJDMjAwMCAnS2xpbWEnIFdvcmRzIC0gUmVsYXRpdmUgRnJlcXVlbmNpZXMiKSsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzPWZhY3Rvcihucm93KGNvbl9mcmVxX3RmaWRmKToxKSwKICAgICAgICAgICAgICAgICAgIGxhYmVscz1jb25fZnJlcV90ZmlkZiRmZWF0dXJlKSArCiAgbGFicyh4PU5VTEwsIHk9InRmLWlkZiIpCgp0cGxvdF90ZmlkZl9jMjAwMApgYGAKIyMgQ29tcGFyaXNvbiBvZiBHcm91cHMvT3JpZ2luCkFkZGl0aW9uYWxseSwgbGV0J3MgaGF2ZSBhIGxvb2sgYXQgdGhlIGNsaW1hdGUgY2hhbmdlIHRlcm1zIGZvciBlYWNoIHdlYnNpdGUgd2UgY3JlYXRlZCBvdXIgY29ycG9yYSBmcm9tLiBBbGwgZXhjZXB0IGZyb20gRUlLRSBhcmUgdXNlZCB0byBjb25zdHJ1Y3QgdGhlIGFjdGl2aXN0cyBjb3JwdXMuIApgYGB7cn0KZGZtX3dlaWdodF9vcmlnaW4gPC0gZnVsbF9jb3JwdXMgJT4lCiAgdG9rZW5zKHJlbW92ZV9wdW5jdCA9IFRSVUUpICU+JQogIHRva2Vuc19yZW1vdmUoZGVfc3RvcHdvcmRzMSkgJT4lCiAgZGZtKCkgJT4lCiAgZGZtX3dlaWdodChzY2hlbWUgPSAicHJvcCIpCgpkZm1fa2xpbWEgPC0gZGZtX3NlbGVjdChkZm1fd2VpZ2h0X29yaWdpbiwgcGF0dGVybiA9ImtsaW1hKiIpCgojIHVzZSB0aGlzIGxpbmUgaW5zdGVhZCBvZiB0aGUgb25lIGFib3ZlIHRvIGdldCAia2xpbWEiIHRlcm1zIApmcmVxX3dlaWdodCA8LSB0ZXh0c3RhdF9mcmVxdWVuY3koZGZtX2tsaW1hLCBuPTEwLCBncm91cHM9ZGZtX3dlaWdodF9vcmlnaW4kb3JpZ2luKQoKZ2dwbG90KGRhdGEgPSBmcmVxX3dlaWdodCwgYWVzKHggPSBucm93KGZyZXFfd2VpZ2h0KToxLCB5ID0gZnJlcXVlbmN5KSkgKwogICAgIGdlb21fcG9pbnQoKSArCiAgICAgZmFjZXRfd3JhcCh+IGdyb3VwLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgICBjb29yZF9mbGlwKCkgKwogICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBucm93KGZyZXFfd2VpZ2h0KToxLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBmcmVxX3dlaWdodCRmZWF0dXJlKSArCiAgICAgbGFicyh4ID0gTlVMTCwgeSA9ICJSZWxhdGl2ZSBmcmVxdWVuY3kiKQoKI2dnc2F2ZSgiZmlndXJlX1BMT1QucG5nIiwgZHBpPTMwMCwgZGV2PSdwbmcnLCBoZWlnaHQ9MTAsIHdpZHRoPTEwLCB1bml0cz0iaW4iKQpgYGAKVGhlIGZvbGxvd2luZyBwbG90IHByb3ZpZGVzIGEgbG90IG9mIGluZm9ybWF0aW9uIGFib3V0IHRoZSB1c2FnZSBvZiB0ZXJtcyBiZXR3ZWVuIGJvdGggZ3JvdXBzIC0gYWN0aXZpc3RzIGFuZCBzY2VwdGljcy4gCmBgYHtyfQpmcmVxc19wcm8gPC0gdGV4dHN0YXRfZnJlcXVlbmN5KHAyMDAwX2tsaW1hX3dlaWdodCkKZnJlcXNfY29uIDwtIHRleHRzdGF0X2ZyZXF1ZW5jeShjMjAwMF9rbGltYV93ZWlnaHQpCgojcGxvdHRpbmcgCmZyZXFzLmFjdCA8LSBmaWx0ZXIoZnJlcXNfcHJvKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBzZWxlY3QoZmVhdHVyZSwgZnJlcXVlbmN5KQpmcmVxcy5zY2VwdCA8LSBmaWx0ZXIoZnJlcXNfY29uKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBzZWxlY3QoZmVhdHVyZSwgZnJlcXVlbmN5KQpmcmVxcyA8LSBsZWZ0X2pvaW4oZnJlcXMuYWN0LCBmcmVxcy5zY2VwdCwgYnkgPSAiZmVhdHVyZSIpICU+JSBoZWFkKDMwKSAlPiUgYXJyYW5nZShmcmVxdWVuY3kueCkgJT4lIG11dGF0ZShmZWF0dXJlID0gZmFjdG9yKGZlYXR1cmUsIGZlYXR1cmUpKQpwIDwtIGdncGxvdChmcmVxcykgKwogICAgZ2VvbV9zZWdtZW50KGFlcyh4PWZlYXR1cmUsIHhlbmQ9ZmVhdHVyZSwgeT1mcmVxdWVuY3kueCwgeWVuZD1mcmVxdWVuY3kueSksIGNvbG9yPSJncmV5IikgKwogICAgZ2VvbV9wb2ludChhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeS54LCBjb2xvdXI9IkFjdGl2aXN0cyIpLCBzaXplID0gMykgKwogICAgZ2VvbV9wb2ludChhZXMoeD1mZWF0dXJlLCB5PWZyZXF1ZW5jeS55LCBjb2xvdXI9IlNjZXB0aWNzIiksIHNpemUgPSAzKSArCiAgICBnZ3RpdGxlKCJDb21wYXJpc29uICdLbGltYScgV2VpZ2h0ZWQgV29yZCBGcmVxdWVuY2llcyBwZXIgR3JvdXAiKSArIAogICAgeGxhYigiIikgKyB5bGFiKCJSZWxhdGl2ZSBGcmVxdWVuY3kiKSArCiAgICBjb29yZF9mbGlwKCkKCnArbGFicyhjb2xvdXI9Ikdyb3VwIikKCmdnc2F2ZSgiY29tcGFyaXNvbl9rbGltYV9mcmVxcy5wbmciLCBkcGk9MzAwLCBkZXY9J3BuZycsIGhlaWdodD02LCB3aWR0aD0xMiwgdW5pdHM9ImluIikKCmBgYAojIyMgV29yZCBDb250ZXh0CgojIyBDb2xsb2NhdGlvbnMKYGBge3J9CiMgdHJhbnNmb3JtIHN0b3BsaXN0cyBmb3IgZHBseXI6OmZpbHRlciBmdW5jdGlvbiAKZGVfc3RwcyA8LSBwYXN0ZTAoZGVfc3RvcHdvcmRzLCBjb2xsYXBzZSA9ICJcXGJ8XFxiIikKZW5fc3RwcyA8LSBwYXN0ZTAoZW5fc3RvcHdvcmRzLCBjb2xsYXBzZSA9ICJcXGJ8XFxiIikKCiMgY2FsY3VsYXRlIGNvbGxvY2F0aW9uIHZpYSB0ZXh0c3RhdApwX2NvbGwgPC0gdGV4dHN0YXRfY29sbG9jYXRpb25zKHBybzIwMDAsIG1pbl9jb3VudD01MCkKY19jb2xsIDwtIHRleHRzdGF0X2NvbGxvY2F0aW9ucyhjb250cmEyMDAwLCBtaW5fY291bnQ9NTApCgojIHJlbW92ZSBlbnRyaWVzIGludm9sdmluZyBzdG9wd29yZHM6CnAyMDAwX2NvbGxfY2xlYW4gPC0gcF9jb2xsICU+JQogIGRwbHlyOjpmaWx0ZXIoIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sIGRlX3N0cHMpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sIGVuX3N0cHMpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICI9IiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIjAwIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIjMwIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIj4iKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAibmV3c2xldHRlciIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJhbm1lbGRlbiIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJcXCsiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiNDAiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiODEiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiZXJuZXVlcmJhcmVyIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIlxcfCIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJPV0xJVCIpKQoKI3AyMDAwX2NvbGxfY2xlYW4KcDIwMDBfY29sbHMgPC0gaGVhZChhcnJhbmdlKHAyMDAwX2NvbGxfY2xlYW4sIGRlc2MoY291bnQpKSwgbj01MCkKCmMyMDAwX2NvbGxfY2xlYW4gPC0gY19jb2xsICU+JQogIGRwbHlyOjpmaWx0ZXIoIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sIGRlX3N0cHMpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sIGVuX3N0cHMpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICI9IiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIjAwIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIjMwIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIj4iKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAibmV3c2xldHRlciIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJhbm1lbGRlbiIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJcXCsiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiNDAiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiODEiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiZXJuZXVlcmJhcmVyIiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgIlxcfCIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJldCIpLAogICAgICAgICAgICAgICAgIXN0cl9kZXRlY3QoY29sbG9jYXRpb24sICJcXMK0IiksCiAgICAgICAgICAgICAgICAhc3RyX2RldGVjdChjb2xsb2NhdGlvbiwgImRhc3MiKSwKICAgICAgICAgICAgICAgICFzdHJfZGV0ZWN0KGNvbGxvY2F0aW9uLCAiXFxeIikpCgojcDIwMDBfY29sbF9jbGVhbgpjMjAwMF9jb2xscyA8LSBoZWFkKGFycmFuZ2UoYzIwMDBfY29sbF9jbGVhbiwgZGVzYyhjb3VudCkpLCBuPTUwKQoKcDIwMDBfY29sbHMKYzIwMDBfY29sbHMKYGBgCgpgYGB7cn0KcDIwMDBfY29sbHMkY29sbG9jYXRpb24gPC0gd2l0aChwMjAwMF9jb2xscywgcmVvcmRlcihjb2xsb2NhdGlvbiwgLWNvdW50KSkKcGxvdDkgPC0gZ2dwbG90KHAyMDAwX2NvbGxzLCBhZXMoeD1jb2xsb2NhdGlvbiwgeT1jb3VudCkpICsgCiAgZ2VvbV9wb2ludCgpK2dndGl0bGUoIlAyMDAwIENvbGxvY2F0aW9uIEZyZXF1ZW5jaWVzIikrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsaGp1c3Q9MSkpCnBsb3Q5IAoKZ2dzYXZlKHBsb3Q9cGxvdDksIHdpZHRoID0gMTAsIGhlaWdodCA9IDUsIGRwaT0zMDAsIGZpbGVuYW1lPSJwMjAwMF9jb2xscy5wbmciKQoKYzIwMDBfY29sbHMkY29sbG9jYXRpb24gPC0gd2l0aChjMjAwMF9jb2xscywgcmVvcmRlcihjb2xsb2NhdGlvbiwgLWNvdW50KSkKcGxvdDEwIDwtIGdncGxvdChjMjAwMF9jb2xscywgYWVzKHg9Y29sbG9jYXRpb24sIHk9Y291bnQpKSArIAogIGdlb21fcG9pbnQoKStnZ3RpdGxlKCJDMjAwMCBDb2xsb2NhdGlvbiBGcmVxdWVuY2llcyIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLGhqdXN0PTEpKQpwbG90MTAKCmdnc2F2ZShwbG90PXBsb3QxMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSwgZHBpPTMwMCwgZmlsZW5hbWU9ImMyMDAwX2NvbGxzLnBuZyIpCmBgYAojIyBLZXluZXNzCmBgYHtyfQojIENyZWF0ZSBhIGRmbSBncm91cGVkIGJ5IGNvbW11bml0eQpncm91cF9kZm0gPC0gdG9rZW5zKGZ1bGxfY29ycHVzLCByZW1vdmVfcHVuY3QgPSBUUlVFKSAlPiUKICB0b2tlbnNfcmVtb3ZlKGRlX3N0b3B3b3JkczEpICU+JQogIHRva2Vuc19ncm91cChncm91cHMgPSBncm91cCkgJT4lCiAgZGZtKCkKCmdyb3VwX2RmbV9rbGltYSA8LSBkZm1fc2VsZWN0KGdyb3VwX2RmbSwgcGF0dGVybiA9ImtsaW1hKiIpCgojIENhbGN1bGF0ZSBrZXluZXNzIGFuZCBkZXRlcm1pbmUgYWN0aXZpc3RzIGFzIHRhcmdldCBncm91cApyZXN1bHRfa2V5bmVzcyA8LSB0ZXh0c3RhdF9rZXluZXNzKGNvcnBfZGZtX2tsaW1hLCB0YXJnZXQgPSAiYWN0aXZpc3RzIikKCiMgUGxvdCBlc3RpbWF0ZWQgd29yZCBrZXluZXNzCnRleHRwbG90X2tleW5lc3MocmVzdWx0X2tleW5lc3MsIG1hcmdpbj0wLjIsIG49MTUsIGNvbG9yPWMoImxpZ2h0Ymx1ZSIsICJyZWQiKSkgCmBgYAojIyBLZXl3b3JkIGluIENvbnRleHQKYGBge3J9Cmt3aWNfcHJvIDwtIGt3aWMocHJvMjAwMCwgcGF0dGVybj0ia2xpbWFzY2h1dHoiLCB3aW5kb3c9NSkgJT4lCiAgYXNfdGliYmxlKCkKCmhlYWQoa3dpY19wcm8sIG49MjApCgojd3JpdGUuY3N2KGt3aWNfcHJvLCAia3dpY19wcm9fa2xpbWFzY2h1dHouY3N2IikKYGBgCgpgYGB7cn0Ka3dpY19jb24gPC0ga3dpYyhjb250cmEyMDAwLCBwYXR0ZXJuPSJrbGltYXNjaHV0eiIsIHdpbmRvdz01KSAlPiUKICBhc190aWJibGUoKQoKaGVhZChrd2ljX2Nvbiwgbj0yMCkKYGBgCgpgYGB7cn0Ka3dpY19jb24gPC0ga3dpYyhjb250cmEyMDAwLCBwYXR0ZXJuPSJrbGltYWtyaXNlIiwgd2luZG93PTUpICU+JQogIGFzX3RpYmJsZSgpCgpoZWFkKGt3aWNfY29uLCBuPTIwKQpgYGAKCmBgYHtyfQprd2ljX2NvbiA8LSBrd2ljKGNvbnRyYTIwMDAsIHBhdHRlcm49ImtsaW1haHlzdGVyaWUiLCB3aW5kb3c9NSkgJT4lCiAgYXNfdGliYmxlKCkKCmhlYWQoa3dpY19jb24sIG49MjApCgp3cml0ZS5jc3YoaGVhZChrd2ljX2Nvbiwgbj0yMCksICJrd2ljX2Nvbl9rbGltYWh5c3RlcmllLmNzdiIpCmBgYAoKYGBge3J9Cmt3aWNfcHJvIDwtIGt3aWMocHJvMjAwMCwgcGF0dGVybj0ia2xpbWFrcmlzZSIsIHdpbmRvdz01KSAlPiUKICBhc190aWJibGUoKQoKaGVhZChrd2ljX3Bybywgbj0yMCkKCndyaXRlLmNzdihoZWFkKGt3aWNfcHJvLCBuPTIwKSwgImt3aWNfcHJvX2tsaW1ha3Jpc2UuY3N2IikKYGBgCgoK